package com.ruoyi.clinic.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.ruoyi.clinic.domain.ClinicCity;
import com.ruoyi.clinic.domain.ClinicDoctorAttachment;
import com.ruoyi.clinic.domain.ClinicProvince;
import com.ruoyi.clinic.dto.clinicdoctor.*;
import com.ruoyi.clinic.mapper.ClinicCityMapper;
import com.ruoyi.clinic.mapper.ClinicDoctorAttachmentMapper;
import com.ruoyi.clinic.mapper.ClinicProvinceMapper;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.ClinicConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ExceptionUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.common.utils.html.EscapeUtil;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysUserService;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.clinic.mapper.ClinicDoctorInfoMapper;
import com.ruoyi.clinic.domain.ClinicDoctorInfo;
import com.ruoyi.clinic.service.IClinicDoctorInfoService;
import com.ruoyi.common.core.text.Convert;
import org.springframework.transaction.annotation.Transactional;

/**
 * 医生信息Service业务层处理
 *
 * @author Tommy
 * @date 2025-11-08
 */
@Service
@Slf4j
public class ClinicDoctorInfoServiceImpl implements IClinicDoctorInfoService {

    @Autowired
    private ClinicDoctorInfoMapper clinicDoctorInfoMapper;

    @Autowired
    private ClinicDoctorAttachmentMapper clinicDoctorAttachmentMapper;

    @Autowired
    private ClinicProvinceMapper clinicProvinceMapper;

    @Autowired
    private ClinicCityMapper clinicCityMapper;

    @Autowired
    protected Validator validator;

    @Autowired
    private ISysDeptService deptService;

    @Autowired
    private ISysUserService userService;

    /**
     * 查询医生信息
     *
     * @param doctorId 医生信息主键
     * @return 医生信息
     */
    @Override
    public ClinicDoctorInfo selectClinicDoctorInfoByDoctorId(Long doctorId) {
        return clinicDoctorInfoMapper.selectClinicDoctorInfoByDoctorId(doctorId);
    }

    @Override
    public ClinicDoctorDetailDTO queryClinicDoctorDetail(Long doctorId, SysUser sysUser) {
        ClinicDoctorInfo clinicDoctorInfo = clinicDoctorInfoMapper.selectClinicDoctorInfoByDoctorId(doctorId);
        if (null == clinicDoctorInfo) {
            return null;
        }
        ClinicDoctorDetailDTO clinicDoctorDetailDTO = BeanUtil.copyProperties(clinicDoctorInfo, ClinicDoctorDetailDTO.class);
        // 查询医生附件信息
        List<ClinicDoctorAttachment> attachments = clinicDoctorAttachmentMapper.selectListByDoctorIdAndAttachmentType(clinicDoctorInfo.getDoctorId(), ClinicConstants.ClinicDoctorAttachmentTypeEnum._OTHER.getType());
        if (CollectionUtil.isEmpty(attachments)) {
            return clinicDoctorDetailDTO;
        }
        List<String> otherImageUrlList = attachments.stream().map(ClinicDoctorAttachment::getAttachmentPath).filter(StringUtils::isNotEmpty).toList();
        clinicDoctorDetailDTO.setOtherImage(String.join(",", otherImageUrlList));
        return this.convertClinicDoctorDetailDTO(clinicDoctorDetailDTO, sysUser);
    }

    /**
     * 详情DTO转换
     *
     * @param clinicDoctorDetailDTO 详情DTO
     * @param sysUser               当前用户
     * @return ClinicDoctorDetailDTO
     */
    private ClinicDoctorDetailDTO convertClinicDoctorDetailDTO(ClinicDoctorDetailDTO clinicDoctorDetailDTO, SysUser sysUser) {
        String isShowSensitivePhone = sysUser.getIsShowSensitivePhone();
        String isShowSensitiveWeixin = sysUser.getIsShowSensitiveWeixin();
        // 1.只有admin用户可以查看手机号和微信号，其他用户根据系统设置可以查看
        if (!sysUser.isAdmin()) {
            clinicDoctorDetailDTO.setMobile(ClinicConstants.YesOrNoEnum._YES.getType().equals(isShowSensitivePhone) ? clinicDoctorDetailDTO.getMobile() : ClinicConstants.MASK);
            clinicDoctorDetailDTO.setWeixin(ClinicConstants.YesOrNoEnum._YES.getType().equals(isShowSensitiveWeixin) ? clinicDoctorDetailDTO.getWeixin() : ClinicConstants.MASK);
        }
        return clinicDoctorDetailDTO;
    }

    /**
     * 查询医生信息列表，带数据权限
     *
     * @param dto 前端查询入参
     * @return 医生信息
     */
    @DataScope(deptAlias = "d", userAlias = "u")
    @Override
    public List<ClinicDoctorResDTO> queryPageList(ClinicDoctorReqDTO dto, SysUser sysUser) {
        List<ClinicDoctorResDTO> clinicDoctorResDTOS = clinicDoctorInfoMapper.queryPageList(dto);
        return this.convertClinicDoctorResDTOList(clinicDoctorResDTOS, sysUser);
    }

    /**
     * 查询结果集覆盖
     *
     * @param clinicDoctorResDTOS 查询返回结果集
     * @param sysUser             当前用户
     */
    private List<ClinicDoctorResDTO> convertClinicDoctorResDTOList(List<ClinicDoctorResDTO> clinicDoctorResDTOS, SysUser sysUser) {
        String isShowSensitivePhone = sysUser.getIsShowSensitivePhone();
        String isShowSensitiveWeixin = sysUser.getIsShowSensitiveWeixin();
        for (ClinicDoctorResDTO resDTO : clinicDoctorResDTOS) {
            // 1.只有admin用户可以查看手机号和微信号，其他用户根据系统设置可以查看
            if (!sysUser.isAdmin()) {
                resDTO.setMobile(ClinicConstants.YesOrNoEnum._YES.getType().equals(isShowSensitivePhone) ? resDTO.getMobile() : ClinicConstants.MASK);
                resDTO.setWeixin(ClinicConstants.YesOrNoEnum._YES.getType().equals(isShowSensitiveWeixin) ? resDTO.getWeixin() : ClinicConstants.MASK);
            }
        }
        return clinicDoctorResDTOS;
    }

    /**
     * 查询医生信息列表，只查询我创建的医生
     *
     * @param dto 前端查询入参
     * @return 医生信息
     */
    @Override
    public List<ClinicDoctorResDTO> queryMyDoctorPageList(ClinicDoctorReqDTO dto, SysUser sysUser) {
        List<ClinicDoctorResDTO> clinicDoctorResDTOS = clinicDoctorInfoMapper.queryMyDoctorPageList(dto);
        return this.convertClinicDoctorResDTOList(clinicDoctorResDTOS, sysUser);
    }

    @Override
    public String importData(List<ClinicDoctorImportDTO> doctorImportDTOList, boolean updateSupport, SysUser sysUser) {
        if (StringUtils.isNull(doctorImportDTOList) || doctorImportDTOList.isEmpty()) {
            throw new ServiceException("导入医生数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        // 根据 身份证号查询
        List<String> identityCardNumList = doctorImportDTOList.stream().map(ClinicDoctorImportDTO::getIdentityCardNum).toList();
        List<ClinicDoctorInfo> clinicDoctorInfos = this.clinicDoctorInfoMapper.selectListByIdentityCardNums(identityCardNumList);
        Map<String, ClinicDoctorInfo> clinicDoctorInfoMap = clinicDoctorInfos.stream().collect(Collectors.toMap(ClinicDoctorInfo::getIdentityCardNum, val -> val, (v1, v2) -> v2));
        // 根据 省份名称查询
        List<String> provinceNameList = doctorImportDTOList.stream().map(ClinicDoctorImportDTO::getProvinceName).toList();
        List<ClinicProvince> clinicProvinces = this.clinicProvinceMapper.selectListByNames(provinceNameList);
        Map<String, ClinicProvince> clinicProvinceMap = clinicProvinces.stream().collect(Collectors.toMap(ClinicProvince::getName, val -> val, (v1, v2) -> v2));
        // 根据 城市名称查询
        List<String> cityNameList = doctorImportDTOList.stream().map(ClinicDoctorImportDTO::getCityName).toList();
        List<ClinicCity> clinicCities = this.clinicCityMapper.selectListByNames(cityNameList);
        Map<String, ClinicCity> clinicCitieMap = clinicCities.stream().collect(Collectors.toMap(ClinicCity::getName, val -> val, (v1, v2) -> v2));
        for (ClinicDoctorImportDTO importDTO : doctorImportDTOList) {
            String doctorName = importDTO.getDoctorName();
            String identityCardNum = importDTO.getIdentityCardNum();
            try {
                // 入参非空校验
                BeanValidators.validateWithException(validator, importDTO);
                // 入参格式校验
                this.checkClinicDoctorImportDTO(importDTO);
                ClinicProvince clinicProvince = clinicProvinceMap.get(importDTO.getProvinceName());
                if (null == clinicProvince) {
                    throw new ServiceException(String.format("根据所在省份名称【%s】，获取不到对应省份", importDTO.getProvinceName()));
                }
                ClinicCity clinicCity = clinicCitieMap.get(importDTO.getCityName());
                if (null == clinicCity) {
                    throw new ServiceException(String.format("根据所在城市名称【%s】，获取不到对应城市", importDTO.getCityName()));
                }
                // 验证合法性
                ClinicDoctorInfo clinicDoctorInfo = clinicDoctorInfoMap.get(importDTO.getIdentityCardNum());
                if (null == clinicDoctorInfo) {
                    // 校验数据权限
                    deptService.checkDeptDataScope(importDTO.getCreateDept()); // 校验部门数据权限
                    ClinicDoctorInfo addClinicDoctorInfo = this.buildClinicDoctorInfo(importDTO, clinicProvinceMap, clinicCitieMap);
                    this.clinicDoctorInfoMapper.insertClinicDoctorInfo(addClinicDoctorInfo);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、医生姓名 " + doctorName + "(" + identityCardNum + ")" + " 导入成功");
                } else if (updateSupport) {
                    // 校验数据权限
                    userService.checkUserDataScope(importDTO.getUpdateById());  // 校验用户数据权限
                    deptService.checkDeptDataScope(importDTO.getCreateDept());  // 校验部门数据权限
                    ClinicDoctorInfo updateClinicDoctorInfo = this.buildClinicDoctorInfo(importDTO, clinicProvinceMap, clinicCitieMap);
                    updateClinicDoctorInfo.setDoctorId(clinicDoctorInfo.getDoctorId());
                    this.clinicDoctorInfoMapper.updateClinicDoctorInfo(updateClinicDoctorInfo);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、医生姓名 " + doctorName + "(" + identityCardNum + ")" + " 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、医生姓名 " + doctorName + "(" + identityCardNum + ")" + " 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                if (ExceptionUtil.isCausedBy(e, ConstraintViolationException.class)) {
                    doctorName = EscapeUtil.clean(doctorName);
                    identityCardNum = EscapeUtil.clean(identityCardNum);
                }
                String msg = "<br/>" + failureNum + "、医生姓名 " + doctorName + "(" + identityCardNum + ")" + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public String importMyDoctorData(List<ClinicDoctorImportDTO> doctorImportDTOList, boolean updateSupport, SysUser sysUser) {
        if (StringUtils.isNull(doctorImportDTOList) || doctorImportDTOList.isEmpty()) {
            throw new ServiceException("导入医生数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        // 根据 身份证号查询
        List<String> identityCardNumList = doctorImportDTOList.stream().map(ClinicDoctorImportDTO::getIdentityCardNum).toList();
        List<ClinicDoctorInfo> clinicDoctorInfos = this.clinicDoctorInfoMapper.selectListByIdentityCardNums(identityCardNumList);
        Map<String, ClinicDoctorInfo> clinicDoctorInfoMap = clinicDoctorInfos.stream().collect(Collectors.toMap(ClinicDoctorInfo::getIdentityCardNum, val -> val, (v1, v2) -> v2));
        // 根据 省份名称查询
        List<String> provinceNameList = doctorImportDTOList.stream().map(ClinicDoctorImportDTO::getProvinceName).toList();
        List<ClinicProvince> clinicProvinces = this.clinicProvinceMapper.selectListByNames(provinceNameList);
        Map<String, ClinicProvince> clinicProvinceMap = clinicProvinces.stream().collect(Collectors.toMap(ClinicProvince::getName, val -> val, (v1, v2) -> v2));
        // 根据 城市名称查询
        List<String> cityNameList = doctorImportDTOList.stream().map(ClinicDoctorImportDTO::getCityName).toList();
        List<ClinicCity> clinicCities = this.clinicCityMapper.selectListByNames(cityNameList);
        Map<String, ClinicCity> clinicCitieMap = clinicCities.stream().collect(Collectors.toMap(ClinicCity::getName, val -> val, (v1, v2) -> v2));
        for (ClinicDoctorImportDTO importDTO : doctorImportDTOList) {
            String doctorName = importDTO.getDoctorName();
            String identityCardNum = importDTO.getIdentityCardNum();
            try {
                // 入参非空校验
                BeanValidators.validateWithException(validator, importDTO);
                // 入参格式校验
                this.checkClinicDoctorImportDTO(importDTO);
                ClinicProvince clinicProvince = clinicProvinceMap.get(importDTO.getProvinceName());
                if (null == clinicProvince) {
                    throw new ServiceException(String.format("根据所在省份名称【%s】，获取不到对应省份",importDTO.getProvinceName()));
                }
                ClinicCity clinicCity = clinicCitieMap.get(importDTO.getCityName());
                if (null == clinicCity) {
                    throw new ServiceException(String.format("根据所在城市名称【%s】，获取不到对应城市", importDTO.getCityName()));
                }
                // 验证合法性
                ClinicDoctorInfo clinicDoctorInfo = clinicDoctorInfoMap.get(importDTO.getIdentityCardNum());
                if (null == clinicDoctorInfo) {
                    // 校验数据权限
                    userService.checkUserDataScope(importDTO.getUpdateById()); // 校验用户数据权限
                    ClinicDoctorInfo addClinicDoctorInfo = this.buildClinicDoctorInfo(importDTO, clinicProvinceMap, clinicCitieMap);
                    this.clinicDoctorInfoMapper.insertClinicDoctorInfo(addClinicDoctorInfo);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、医生姓名 " + doctorName + "(" + identityCardNum + ")" + " 导入成功");
                } else if (updateSupport) {
                    userService.checkUserDataScope(importDTO.getUpdateById());  // 校验用户数据权限
                    // 校验是否是我负责的医生
                    Long createById = clinicDoctorInfo.getCreateById();
                    Long createDept = clinicDoctorInfo.getCreateDept();
                    if (!(importDTO.getUpdateById().equals(createById) && importDTO.getCreateDept().equals(createDept))) {
                        throw new ServiceException(String.format("医生姓名 %s(%s) 不是当前用户所负责的，不支持修改", doctorName, identityCardNum));
                    }
                    ClinicDoctorInfo updateClinicDoctorInfo = this.buildClinicDoctorInfo(importDTO, clinicProvinceMap, clinicCitieMap);
                    updateClinicDoctorInfo.setDoctorId(clinicDoctorInfo.getDoctorId());
                    this.clinicDoctorInfoMapper.updateClinicDoctorInfo(updateClinicDoctorInfo);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、医生姓名 " + doctorName + "(" + identityCardNum + ")" + " 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、医生姓名 " + doctorName + "(" + identityCardNum + ")" + " 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                if (ExceptionUtil.isCausedBy(e, ConstraintViolationException.class)) {
                    doctorName = EscapeUtil.clean(doctorName);
                    identityCardNum = EscapeUtil.clean(identityCardNum);
                }
                String msg = "<br/>" + failureNum + "、医生姓名 " + doctorName + "(" + identityCardNum + ")" + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    /**
     * 导入字段，格式校验
     *
     * @param importDTO 导入参数
     */
    private void checkClinicDoctorImportDTO(ClinicDoctorImportDTO importDTO) {
        List<String> yesOrNoList = Arrays.asList(ClinicConstants.YesOrNoEnum._YES.getType(), ClinicConstants.YesOrNoEnum._NO.getType());
        List<String> poinTypeList = Arrays.asList(ClinicConstants.PointTypeEnum._ONLY.getType(), ClinicConstants.PointTypeEnum._MORE.getType());
        String isFiveExperience = importDTO.getIsFiveExperience();
        if (!yesOrNoList.contains(isFiveExperience)) {
            throw new ServiceException("是否满5年(是/否)，格式不正确");
        }
        String isFullTimeJob = importDTO.getIsFullTimeJob();
        if (!yesOrNoList.contains(isFullTimeJob)) {
            throw new ServiceException("是否全职(是/否)，格式不正确");
        }
        String isDirector = importDTO.getIsDirector();
        if (!yesOrNoList.contains(isDirector)) {
            throw new ServiceException("是否负责人(是/否)，格式不正确");
        }
        String isLegalPerson = importDTO.getIsLegalPerson();
        if (!yesOrNoList.contains(isLegalPerson)) {
            throw new ServiceException("是否法人(是/否)，格式不正确");
        }
        String pointType = importDTO.getPointType();
        if (!poinTypeList.contains(pointType)) {
            throw new ServiceException("多点类型(唯一点/多点)，格式不正确");
        }
        String isPresent = importDTO.getIsPresent();
        if (!yesOrNoList.contains(isPresent)) {
            throw new ServiceException("是否到场(是/否)，格式不正确");
        }
        String expectSalaryStr = importDTO.getExpectSalaryStr();
        try {
            new BigDecimal(expectSalaryStr);
        } catch (Exception e) {
            throw new ServiceException("期望薪水，格式不正确");
        }
    }

    /**
     * 对象转换
     *
     * @param importDTO 导入数据DTO
     * @return ClinicDoctorInfo
     */
    private ClinicDoctorInfo buildClinicDoctorInfo(ClinicDoctorImportDTO importDTO,
                                                   Map<String, ClinicProvince> clinicProvinceMap,
                                                   Map<String, ClinicCity> clinicCitieMap) {
        ClinicDoctorInfo clinicDoctorInfo = BeanUtil.copyProperties(importDTO, ClinicDoctorInfo.class);
        ClinicProvince clinicProvince = clinicProvinceMap.get(importDTO.getProvinceName());
        ClinicCity clinicCity = clinicCitieMap.get(importDTO.getCityName());
        try {
            clinicDoctorInfo.setExpectSalary(new BigDecimal(importDTO.getExpectSalaryStr()));
        } catch (Exception e) {
            log.error("期望薪水格式不正确, {}", importDTO.getExpectSalaryStr());
        }
        if (null != clinicProvince) {
            clinicDoctorInfo.setProvinceId(clinicProvince.getId());
        } else {
            clinicDoctorInfo.setProvinceId(null);
            clinicDoctorInfo.setProvinceName(null);
        }
        if (null != clinicCity) {
            clinicDoctorInfo.setCityId(clinicCity.getId());
        } else {
            clinicDoctorInfo.setCityId(null);
            clinicDoctorInfo.setCityName(null);
        }
        return clinicDoctorInfo;
    }

    /**
     * 新增医生信息
     *
     * @param dto 医生信息
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertClinicDoctorInfo(ClinicDoctorUpdateDTO dto) {
        dto.setCreateTime(DateUtils.getNowDate());
        dto.setUpdateTime(DateUtils.getNowDate());
        // 根据省份ID和城市ID，查询名称
        ClinicProvince clinicProvince = clinicProvinceMapper.selectClinicProvinceById(dto.getProvinceId());
        ClinicCity clinicCity = clinicCityMapper.selectClinicCityById(dto.getCityId());
        // 1.校验
        this.checkCreate(dto);
        // 2.新增
        Long doctorId = this.doCreateClinicDoctorInfo(dto, clinicProvince, clinicCity);
        // 其他证件
        this.doCreateClinicDoctorAttachment(doctorId, dto);
        return ClinicConstants.ONE_INT;
    }

    /**
     * 新增交易逻辑
     *
     * @param dto 前端入参
     */
    private void checkCreate(ClinicDoctorUpdateDTO dto) {
        // 校验身份证是否存在
        List<ClinicDoctorInfo> clinicDoctorInfos = clinicDoctorInfoMapper.selectListByIdentityCardNum(dto.getIdentityCardNum());
        if (CollectionUtil.isNotEmpty(clinicDoctorInfos)) {
            throw new ServiceException(String.format("新增医生信息，身份证号【%s】已存在", dto.getIdentityCardNum()));
        }
    }

    /**
     * 创建医生信息，并返回主键ID
     *
     * @param dto 前端入参
     * @return 新增返回主键ID
     */
    private Long doCreateClinicDoctorInfo(ClinicDoctorUpdateDTO dto, ClinicProvince clinicProvince, ClinicCity clinicCity) {
        ClinicDoctorInfo clinicDoctorInfo = new ClinicDoctorInfo();
        BeanUtils.copyProperties(dto, clinicDoctorInfo);
        clinicDoctorInfo.setProvinceName(null != clinicProvince ? clinicProvince.getName() : null);
        clinicDoctorInfo.setCityName(null != clinicCity ? clinicCity.getName() : null);
        clinicDoctorInfoMapper.insertClinicDoctorInfo(clinicDoctorInfo);
        return clinicDoctorInfo.getDoctorId();
    }

    /**
     * 保存医生附件列表
     *
     * @param doctorId 医生ID
     * @param dto      前端传入参数
     */
    private void doCreateClinicDoctorAttachment(Long doctorId, ClinicDoctorUpdateDTO dto) {
        if (null == doctorId) {
            return;
        }
        String otherImage = dto.getOtherImage();
        if (StringUtils.isEmpty(otherImage)) {
            return;
        }
        String[] otherImageArray = otherImage.split(",");
        List<ClinicDoctorAttachment> attachmentList = new ArrayList<>(otherImageArray.length);
        for (String one : otherImageArray) {
            ClinicDoctorAttachment attachment = buildClinicDoctorAttachment(doctorId, dto, one);
            attachmentList.add(attachment);
        }
        if (CollectionUtil.isNotEmpty(attachmentList)) {
            attachmentList.forEach(one -> clinicDoctorAttachmentMapper.insertClinicDoctorAttachment(one));
        }
    }

    /**
     * 构建医生附件
     *
     * @param doctorId   医生ID
     * @param dto        前端传入参数
     * @param otherImage 其他图片
     * @return ClinicDoctorAttachment
     */
    private static ClinicDoctorAttachment buildClinicDoctorAttachment(Long doctorId, ClinicDoctorUpdateDTO dto, String otherImage) {
        String attachmentName = otherImage.substring(otherImage.lastIndexOf("/") + 1);
        ClinicDoctorAttachment attachment = new ClinicDoctorAttachment();
        attachment.setDoctorId(doctorId);
        attachment.setAttachmentType(ClinicConstants.ClinicDoctorAttachmentTypeEnum._OTHER.getType());
        attachment.setAttachmentName(attachmentName);
        attachment.setAttachmentPath(otherImage);
        attachment.setCreateById(dto.getCreateById());
        attachment.setCreateBy(dto.getCreateBy());
        attachment.setUpdateById(dto.getUpdateById());
        attachment.setUpdateBy(dto.getUpdateBy());
        return attachment;
    }

    /**
     * 修改医生信息
     *
     * @param dto 前端入参
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateClinicDoctorInfo(ClinicDoctorUpdateDTO dto) {
        dto.setUpdateTime(DateUtils.getNowDate());
        // 根据省份ID和城市ID，查询名称
        ClinicProvince clinicProvince = clinicProvinceMapper.selectClinicProvinceById(dto.getProvinceId());
        ClinicCity clinicCity = clinicCityMapper.selectClinicCityById(dto.getCityId());
        // 1.校验逻辑
        this.checkUpdate(dto);
        // 2.更新操作
        this.doUpdateClinicDoctorInfo(dto, clinicProvince, clinicCity);
        // 3.更新医生附件信息
        this.doUpdateClinicDoctorAttachment(dto);
        return ClinicConstants.ONE_INT;
    }

    /**
     * 编辑校验
     *
     * @param dto 前端入参
     */
    private void checkUpdate(ClinicDoctorUpdateDTO dto) {
        if (null == dto.getDoctorId()) {
            throw new ServiceException("修改医生信息，参数有误");
        }
        // 校验身份证是否有重复
        List<ClinicDoctorInfo> clinicDoctorInfos = clinicDoctorInfoMapper.selectListByIdentityCardNum(dto.getIdentityCardNum());
        if (CollectionUtil.isNotEmpty(clinicDoctorInfos)) {
            // 查询的数据，排除掉ID为自己的，如果还存在则说明有其他重复的
            List<ClinicDoctorInfo> filterClinicDoctorInfos = clinicDoctorInfos.stream().filter(one -> !one.getDoctorId().equals(dto.getDoctorId())).toList();
            if (CollectionUtil.isNotEmpty(filterClinicDoctorInfos)) {
                throw new ServiceException(String.format("编辑医生信息，身份证号【%s】已存在", dto.getIdentityCardNum()));
            }
        }
    }

    /**
     * 更新医生信息
     *
     * @param dto 前端入参
     */
    private void doUpdateClinicDoctorInfo(ClinicDoctorUpdateDTO dto, ClinicProvince clinicProvince, ClinicCity clinicCity) {
        ClinicDoctorInfo clinicDoctorInfo = new ClinicDoctorInfo();
        BeanUtils.copyProperties(dto, clinicDoctorInfo);
        // 手机号
        clinicDoctorInfo.setMobile(ClinicConstants.MASK.equals(dto.getMobile()) ? null : dto.getMobile());
        // 微信
        clinicDoctorInfo.setWeixin(ClinicConstants.MASK.equals(dto.getWeixin()) ? null : dto.getWeixin());
        clinicDoctorInfo.setProvinceName(null != clinicProvince ? clinicProvince.getName() : null);
        clinicDoctorInfo.setCityName(null != clinicCity ? clinicCity.getName() : null);
        clinicDoctorInfoMapper.updateClinicDoctorInfo(clinicDoctorInfo);
    }

    /**
     * 更新医生其他附件信息
     *
     * @param dto 前端入参
     */
    private void doUpdateClinicDoctorAttachment(ClinicDoctorUpdateDTO dto) {
        // 1.先删除之前的数据
        // 2.在创建信息的数据
        clinicDoctorAttachmentMapper.deleteClinicDoctorAttachmentByDoctorId(dto.getDoctorId());
        this.doCreateClinicDoctorAttachment(dto.getDoctorId(), dto);
    }

    /**
     * 批量删除医生信息
     *
     * @param doctorIds 需要删除的医生信息主键
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int deleteClinicDoctorInfoByDoctorIds(String doctorIds) {
        // 1.删除医生信息
        // 2.删除医生附件信息
        clinicDoctorInfoMapper.deleteClinicDoctorInfoByDoctorIds(Convert.toStrArray(doctorIds));
        this.clinicDoctorAttachmentMapper.deleteClinicDoctorAttachmentByDoctorIds(Convert.toStrArray(doctorIds));
        return ClinicConstants.ONE_INT;
    }

    /**
     * 删除医生信息信息
     *
     * @param doctorId 医生信息主键
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int deleteClinicDoctorInfoByDoctorId(Long doctorId) {
        // 1.删除医生信息
        // 2.删除医生附件信息
        clinicDoctorInfoMapper.deleteClinicDoctorInfoByDoctorId(doctorId);
        this.clinicDoctorAttachmentMapper.deleteClinicDoctorAttachmentByDoctorId(doctorId);
        return ClinicConstants.ONE_INT;
    }
}
